package com.ls.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;

import com.ls.config.auth.PyPermission;
import com.ls.config.redis.RedisClient;
import com.ls.config.redis.RedisConfig;
import com.ls.constant.SystemConstants;
import com.ls.entity.LoginRecord;
import com.ls.entity.SysUser;
import com.ls.enums.RoleEnum;
import com.ls.exception.ErrorEnums;
import com.ls.service.ILoginService;
import com.ls.service.ISysUserService;
import com.ls.utils.ResultData;
import com.ls.utils.rsa.RsaUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.ls.constant.SystemConstants.TABLE_NAME_CUSTOMER;
import static com.ls.constant.SystemConstants.TABLE_NAME_USER;


/**
 * @ClassName LoginServiceImpl
 * @Description 登录相关逻辑
 * @Author pengyu
 * @Date 2019/9/15 9:05
 * @Version 1.0
 **/
@SuppressWarnings("ALL")
@Slf4j
@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements ILoginService {

    private final RedisClient redisClient;
    /**
     * service中不允许直接调用除自身对应mapper以外的其他mapper
     */
    private final ISysUserService sysUserService;


    /**
     * 登录有效时间
     */
//    @Value("${shiro.timeout}")
//    private int timeOut;

    /**
     * RSA私钥
     */
    @Value("${RSA.privateKey}")
    private String privateKey;

    /**
     * RSA公钥
     */
    @Value("${RSA.publicKey}")
    private String publicKey;

    /**
     * 登录接口
     *
     * @param phone    账户
     * @param password 密码
     * @return
     */
    @Override
    public ResultData pcLogin(String phone, String password) {
//        ResultData resultPwdData = new ResultData(DEFAULT_PWD.getCode(), DEFAULT_PWD.getMessage());
        ResultData resultPwdData = ResultData.success();
        boolean isDefaultPwd = false;

        SysUser user = sysUserService.findUserByPhone(phone);
        if (user == null) {
            return ResultData.failure(ErrorEnums.UNDEFINED_EXCEPTION.getCode(), "系统无此用户");
        }
        String userPwd = getRsaDecryStr(user.getPassword());
        String loginPwd = getRsaDecryStr(password);
        log.info(" userPwd = " + userPwd);
        log.info(" loginPwd = " + loginPwd);
        if (!userPwd.equals(loginPwd)) {
            return ResultData.failure(ErrorEnums.UNDEFINED_EXCEPTION.getCode(), "密码错误");
        }
        //密码需要解密后判断
        String defaultPassword = phone.substring(phone.length() - 6);
        String plaintext = RsaUtils.getRsaDecryStr(password, privateKey);
        if (defaultPassword.equals(plaintext)) {
//                return ResultData.failure(CommonExceptionEnums.DEFAULT_PWD.getCode(), "系统检测到您使用的是初始密码，请修改！");
//                resultData.setCode(DEFAULT_PWD.getCode());
            isDefaultPwd = true;
        }
        //如果已经登录，就返回无需重复登录 考虑到调试方便，这里就去掉
        Long userId = user.getUserId();
//        if (StpUtil.isLogin(userId) && SystemConstants.PC.equals(StpUtil.getLoginDevice())) {
//            return ResultData.failure(ErrorEnums.ALREADY_LOGIN);
//        }
        StpUtil.login(userId, SystemConstants.PC);

        String token = StpUtil.getTokenInfo().getTokenValue();
        //获取用户权限返回前端
        Long roleId = user.getRoleId();
        if (roleId == null) {
            log.error("用户_{}登录认证异常,异常信息:{}", phone, "登录用户无对应角色！");
        }

        log.info("=====用户{}开始登录，redis保存用户信息token={}", user.getPhone(), token);

        RoleEnum roleEnum = RoleEnum.getRoleEnum(roleId);
        if (roleEnum == null) {
            log.error("用户_{}登录认证异常,异常信息:{},{}", phone, roleId, "登录用户角色无对应枚举！");
        }
        List<String> permissionList = PyPermission.ROLE_MAP.get(roleEnum);
        //更新用户登录次数
        updateUserLoginTimes(user);
        // 必要值返回给前端
        Map<String, Object> map = new HashMap<>(5);
        user.setPassword(null);
        user.setShowName(user.getUserName());
        //TODO PyPermission 把菜单 也加上
//                map.put("menuList", menuList);
        map.put("permissionList", permissionList);
        map.put(SystemConstants.SESSION_USER, user);
        map.put(SystemConstants.SYS_TOKEN, token);
        if (isDefaultPwd) {
            resultPwdData.setData(map);
            return resultPwdData;
        }
        //获取当前 Token 的 Token-Session 对象
        SaSession saSession = StpUtil.getTokenSession();
        saSession.set("phone", phone);
        saSession.set(SystemConstants.PC + "_" + user.getUserId().toString(), user);
        ResultData resultData = ResultData.successData(map);
        resultData.setToken(token);
        resultData.setData(map);
        LoginRecord loginRecord = new LoginRecord();
        loginRecord.setEntityName(TABLE_NAME_USER);
        loginRecord.setEntityId(userId);
        loginRecord.setLoginTime(LocalDateTime.now());
        loginRecord.insert();
        return resultData;
    }
    /**
     * 更新用户登录信息  ,LocalDateTime lastLoginTime
     */
    private void updateUserLoginTimes(SysUser user) {
        LocalDateTime lastLoginTime = user.getUpdateTime();
//        updateTime作为上次登录时间，每次登录后判断上次登录时间与当前时间的比较，如果在3个小时内的话，就把登录时长
//                * 加上 （当前时间 - 上次登录时间）。如果在3个小时外的话，就直接加3个小时。正常退出登录的时候，在logOut的地方计算时间差，加到登录时间里面去。
        LocalDateTime now = LocalDateTime.now();
        Integer userLoginTimes = user.getLoginTimes();
        if (userLoginTimes == null) {
            userLoginTimes = 0;
        }
        Duration duration = Duration.between(lastLoginTime, now);
        int minute = RedisConfig.LOGIN_EXPIRE_MINUTE;
        // 3个小时，180分钟
        if (duration.toMinutes() > minute) {
            userLoginTimes += minute;
        } else {
            userLoginTimes = userLoginTimes + (int) duration.toMinutes();
        }
        //更新登录次数和更新时间
        user.setLoginCount(user.getLoginCount() + 1);
        user.setUpdateTime(LocalDateTime.now());
        user.setLoginTimes(userLoginTimes);
        sysUserService.updateById(user);
    }

    /**
     * RSA解密
     *
     * @param password 需要解密的密码
     * @return 解密后的密码
     */
    public String getRsaDecryStr(String password) {
        //将加密字符串解密并返回
        String replaceStr = password.replace(" ", "+");
        return RsaUtils.decryptDataOnJava(replaceStr, privateKey);
    }

    public static void main(String[] args) {
        String phone = "13012345678";
        String initPassword = phone.substring(phone.length() - 7, phone.length() - 1);
        System.out.println(initPassword);
        String initPassword1 = phone.substring(phone.length() - 6);
        System.out.println(initPassword1);


    }

}
